
#include <air001xx_ll_system.h>
#include <air001xx_ll_pwr.h>
#include <air001xx_ll_rcc.h>
#include <air001xx_ll_utils.h>
#include <hd_flash.h>
#include <hd_oled_font.h>
#include <hd_oled.h>
#include <pd_i2c_hd.h>
#include <hd_oled_protocol_i2c.h>
#include <pd_i2c_sim.h>

/**
  * @brief  系统时钟配置函数
  * @param  无
  * @retval 无
  */
void SystemClock_Config(void) {
    /* 使能HSI */
    LL_RCC_HSI_Enable();
    while (LL_RCC_HSI_IsReady() != 1);

    /* 设置 AHB 分频*/
    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);

    /* 配置HSISYS作为系统时钟源 */
    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSISYS);
    while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSISYS);

    /* 适配 HSI 标准值 */
    LL_RCC_HSI_SetCalibFreq(16000000);

    /* 设置 APB1 分频*/
    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
    LL_Init1msTick(16000000);

    /* 更新系统时钟全局变量SystemCoreClock(也可以通过调用SystemCoreClockUpdate函数更新) */
    LL_SetSystemCoreClock(16000000);
}


#define OLED_I2C            1   // Select a protocol in IIC or SPI
#define OLED_I2C_SIMULATE   1   // Select hardware or software simulate

OLED *oled;

void oled_instance() {
#ifdef OLED_SPI
    GPIO *sckGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_5); // Clock, SPIx_SCK
    GPIO *sdaGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_7); // MOSI,  SPIx_MOSI
    GPIO *resGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_3); // Reset, General IO, the chip reset pin is better
    GPIO *dcGPIO = GPIOBuilder.build(GPIOA, LL_GPIO_PIN_1);  // Data or Command, General IO
    GPIO *csGPIO[] = {
            GPIOBuilder.build(GPIOA, LL_GPIO_PIN_2)      // Chip Select(Slave Select), General IO
    };
    SPIGPIO *spiGPIO = SPIGPIOBuilder.build(csGPIO, 1, sckGPIO, sdaGPIO, NULL);

#ifdef OLED_SPI_SIMULATE
    SPISimulate *spiObj = SPISimulateBuilder.build(spiGPIO);
#elif OLED_SPI_HARDWARE
    SPIHardware *spiObj = SPIHardwareBuilder.build(SPI1, spiGPIO);
#endif
    SPI *spi1 = (SPI *) spiObj;
    spi1->init(spi1);
    OLEDProtocolSPI *oledProtocolObj = OLEDProtocolSPIBuilder.build(spi1, resGPIO, dcGPIO, csGPIO[0]);

#elif OLED_I2C
    GPIO *sckGPIO = GPIOBuilder.build(GPIOF, LL_GPIO_PIN_1);  // I2Cx_SCL
    GPIO *sdaGPIO = GPIOBuilder.build(GPIOF, LL_GPIO_PIN_0);  // I2Cx_SDA
#ifdef OLED_I2C_SIMULATE
    I2CSimulate *i2CObj = I2CSimulateBuilder.build(sckGPIO, sdaGPIO);
#elif OLED_I2C_HARDWARE
    I2CHardware *i2CObj = I2CHardwareBuilder.build(I2C, sckGPIO, sdaGPIO);
#endif
    IIC *i2c = (IIC *) i2CObj;
    i2c->init(i2c);
    OLEDProtocolI2C *oledProtocolObj = OLEDProtocolI2CBuilder.build(i2c);
#endif

    StorageFlash *storageFlash = StorageFlashBuilder.build();
    OLEDFont *oledFont = OLEDFontBuilder.build((Storage *) storageFlash, ENCODING_UTF8);
    oled = OLEDBuilder.build((OLEDProtocol *) oledProtocolObj, oledFont);
    oled->init(oled);
}


/**
  * @brief  错误执行函数
  * @param  无
  * @retval 无
  */
void Error_Handler(void) {
    /* 无限循环 */
    while (1) {
    }
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line) {
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}

#endif /* USE_FULL_ASSERT */


